/*
 * Universidade Estadual de Campinas - UNICAMP
 * MC823 - Laboratório de Redes
 * Alunos:
 *         Daniel Camillo C. Farias  RA: 059878
 *         Vitor Hugo Mickus Rodrigues RA: 072627
 * Professor:
 *         Paulo Lício e Celio
 *
 * Client program for Network Labs. Simulate an ECHO program.
 *
 */

#include "client_echo.h"



/*
 * Main Function, start of the program.
 *      Input:
 *            int argc:  number of parameters passed in command line.
 *            char* argv[]: the parameters passed in command line.
 *      Output:
 *            int : status of the program.             
 */
int main(int argc, char* argv[]) {
  //Local Variables
  int sockfd, numbytes;
  int counter_send = 0, counter_received = 0;
  int max_line_size = 0;
  int count_chars_sent = 0, count_chars_received = 0;
  char send_buf[MAXDATASIZE];
  char receive_buf[MAXDATASIZE];
  struct hostent *he;
  struct sockaddr_in their_addr; /* connector's address information */
  clock_t initialTime;
  FILE *wsock, *rsock;

  //Inicia contagem de tempo
  initialTime = times(NULL);
 
  //Get the host info 
  if ( (he=gethostbyname(argv[1]) ) == NULL) {  
    perror("gethostbyname");
    exit(1);
  }
  
  
  //create socket descriptor
  //   AF_INET -> used domain ( internet )
  //   SOCK_STREAM -> socket type ( pipe type )
  //   0 -> protocol ( should always be 0 )
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }  
    
  their_addr.sin_family = AF_INET;         /* host byte order */
  their_addr.sin_port = htons(PORT);       /* short, network byte order */
  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
  bzero(&(their_addr.sin_zero), 8);        /* zero the rest of the struct */
    
  // Connect to the socket 
  if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
    perror("connect");
    exit(1);
  }  

  if((wsock = fdopen(sockfd, "w"))==NULL) {
    perror("Failed to open fd as writeable FILE *");
  }
  
  if((rsock = fdopen(sockfd, "r"))==NULL) {
    perror("Failed to open fd as readable FILE *");
  }  
  
  // Create child
  switch(fork()) {
    
    // Parent node
  case 0:    
    
    // Receive data from server
    while ( fgets(receive_buf, MAXDATASIZE, rsock) != NULL ) {
      
      // Flush sock
      fflush(rsock);    
      
      // Update controls
      numbytes=strlen(receive_buf);      
      count_chars_received += numbytes;    
      counter_received++;         
      printf("%s",receive_buf);
    }// end of while    

    // Print parent info
    fprintf(stderr, "\n\n----Parent Information----\n");    
    fprintf(stderr,"Received lines: %d\n", counter_received);
    fprintf(stderr,"Total chars received: %d\n", count_chars_received);
    fprintf(stderr,"time: %.1f seconds\n", (double)(times(NULL) - initialTime)/(double)sysconf(_SC_CLK_TCK));
    fprintf(stderr,"--------END--------\n"); 
    break;

    // Case Error
 case -1:
    perror("fork error");
    exit(1);
    break;

    // Child node
  default:  
    //Read data from keyboard
    while ( fgets( send_buf, MAXDATASIZE, stdin ) != NULL ) {        

      // Send data to server
      if (fputs(send_buf, wsock) == NULL) {
	perror("send");
	exit(1);
      }

      fflush(wsock);
      
      // Update Controls
      counter_send++;
      count_chars_sent += strlen(send_buf);
      if(strlen(send_buf)-1 > max_line_size ) {
	max_line_size = strlen(send_buf)-1;
      }

    } // end of while        
    
    // Close socket for write
    shutdown(sockfd, SHUT_WR);    

    //close(sockfd);
    
    // Print some information
    fprintf(stderr, "\n----Child Information----\n");    
    fprintf(stderr,"Sent lines: %d\n", counter_send);
    fprintf(stderr,"Biggest line: %d\n", max_line_size);
    fprintf(stderr,"Total chars sent: %d\n", count_chars_sent);    
    fprintf(stderr,"time: %.1f seconds\n", (double)(times(NULL) - initialTime)/(double)sysconf(_SC_CLK_TCK));
    fprintf(stderr, "---- End ----\n");    

    return 0;
    
  }// end of switch
    
  // Close socket
  close(sockfd);     

  wait(NULL);
  
  return 0;  
}
